﻿using NMock2;
using NMock2.Internal;
using NMock2.Matchers;
using NUnit.Framework;

namespace NMock3.Tests
{
	[TestFixture]
	public class PropertyTests
	{
		MockFactory _factory = new MockFactory();
		private Mock<Iam2Bmocked> _mock;

		[SetUp]
		public void TestSetup()
		{
			_factory.SuppressUnexpectedAndUnmetExpectations();
			_mock = _factory.CreateMock<Iam2Bmocked>();
		}

		[TearDown]
		public void TearDown()
		{
			_factory.VerifyAllExpectationsHaveBeenMet();
		}

		[Test]
		public void WritableWithoutMatcherTest()
		{
			_mock.Expects.One.SetPropertyTo(m => m.Write = "some value").Comment("from WritableWithoutMatcherTest");
			_mock.Expects.One.SetProperty(m => m.Write = "").To("some value").Comment("from WritableWithoutMatcherTest");

			new Driver(_mock.MockObject).SetWrite("some value");
			new Driver(_mock.MockObject).SetWrite("some value");
		}

		[Test]
		public void WritableWithMatcherTest()
		{
			_mock.Expects.One.SetProperty(m => m.Write = "").To(new TypeMatcher(typeof(string))).Comment("from WritableWithMatcherTest");

			new Driver(_mock.MockObject).SetWrite("some other value");
		}

		[Test]
		[ExpectedException(typeof(ExpectationException))]
		public void WritableWithoutMatcherExceptionTest()
		{
			_factory.SuppressUnexpectedAndUnmetExpectations();

			_mock.Expects.One.SetPropertyTo(m => m.Write = "some value").Comment("from WritableWithoutMatcherExceptionTest");

			new Driver(_mock.MockObject).SetWrite("some other value");
		}

		[Test]
		[ExpectedException(typeof(ExpectationException))]
		public void WritableWithMatcherExceptionTest()
		{
			_factory.SuppressUnexpectedAndUnmetExpectations();

			_mock.Expects.One.SetProperty(m => m.Write = "").To(new TypeMatcher(typeof(string))).Comment("from WritableWithMatcherExceptionTest");

			new Driver(_mock.MockObject).SetWrite(null);
		}

		[Test]
		public void ReadWriteWithoutMatcherTest()
		{
			_mock.Expects.One.SetProperty(m => m.ReadWrite = "some value").To("some value1").Comment("from set = x.to");
			_mock.Expects.One.SetProperty(m => m.ReadWrite).To("some value2").Comment("from set.to");
			_mock.Expects.One.SetPropertyTo(m => m.ReadWrite = "some value3").Comment("from setto");

			new Driver(_mock.MockObject).SetReadWrite("some value1");
			new Driver(_mock.MockObject).SetReadWrite("some value2");
			new Driver(_mock.MockObject).SetReadWrite("some value3");

			_mock.Expects.One.GetProperty(m => m.ReadWrite).WillReturn("some other value1");
			_mock.Expects.One.GetProperty(m => m.ReadWrite, "some other value2");

			Assert.AreEqual("some other value1", new Driver(_mock.MockObject).GetReadWrite());
			Assert.AreEqual("some other value2", new Driver(_mock.MockObject).GetReadWrite());

		}

		[Test]
		public void ReadOnlyWithoutMatcherTest()
		{
			_mock.Expects.One.GetProperty(m => m.Read).WillReturn("a value 1");
			_mock.Expects.One.GetProperty(m => m.Read, "a value 2");

			Assert.AreEqual("a value 1", _mock.MockObject.Read);
			Assert.AreEqual("a value 2", _mock.MockObject.Read);
		}

		[Test]
		public void ReadWriteIndexerTest1()
		{
			_mock.Expects.One.GetProperty(m => m[0]).WillReturn("first");
			_mock.Expects.One.GetProperty(m => m[1]).WillReturn("second");
			_mock.Expects.One.GetProperty(m => m[2], "third");

			Assert.AreEqual("first", _mock.MockObject[0]);
			Assert.AreEqual("second", _mock.MockObject[1]);
			Assert.AreEqual("third", _mock.MockObject[2]);

		}

		[Test]
		public void ReadWriteIndexerTest2()
		{
			_mock.Expects.One.SetPropertyTo(m => m[4] = "fourth");
			_mock.Expects.One.SetProperty(m => m[5]).To("fifth");
			_mock.Expects.One.SetProperty(m => m[6] = "VI").To("sixth");

			_mock.MockObject[4] = "fourth";
			_mock.MockObject[5] = "fifth";
			_mock.MockObject[6] = "sixth";
		}
	}
}